define(['jquery', 'underscore', 'backbone', 'gettext', 'js/utils/handle_iframe_binding', 'js/utils/templates',
    'common/js/components/utils/view_utils'],
function($, _, Backbone, gettext, IframeUtils, TemplateUtils, ViewUtils) {
    /*
         This view is extended from backbone to provide useful functionality for all Studio views.
         This functionality includes:
         - automatic expand and collapse of elements with the 'ui-toggle-expansion' class specified
         - additional control of rendering by overriding 'beforeRender' or 'afterRender'

         Note: the default 'afterRender' function calls a utility function 'iframeBinding' which modifies
         iframe src urls on a page so that they are rendered as part of the DOM.
         */

    var BaseView = Backbone.View.extend({
        events: {
            'click .ui-toggle-expansion': 'toggleExpandCollapse'
        },

        options: {
            // UX is moving towards using 'is-collapsed' in preference over 'collapsed',
            // but use the old scheme as the default so that existing code doesn't need
            // to be rewritten.
            collapsedClass: 'collapsed'
        },

        // override the constructor function
        constructor: function(options) {
            _.bindAll(this, 'beforeRender', 'render', 'afterRender');

            // Merge passed options and view's options property and
            // attach to the view's options property
            if (this.options) {
                options = _.extend({}, _.result(this, 'options'), options);
            }

            // trunc is not available in IE, and it provides polyfill for it.
            // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
            if (!Math.trunc) {
                Math.trunc = function(v) {
                    v = +v; // eslint-disable-line no-param-reassign
                    // eslint-disable-next-line no-mixed-operators, no-nested-ternary
                    return (v - v % 1) || (!isFinite(v) || v === 0 ? v : v < 0 ? -0 : 0);
                };
            }
            this.options = options;

            var _this = this;
            // xss-lint: disable=javascript-jquery-insertion
            this.render = _.wrap(this.render, function(render, options) { // eslint-disable-line no-shadow
                _this.beforeRender();
                render(options);
                _this.afterRender();
                return _this;
            });

            // call Backbone's own constructor
            Backbone.View.prototype.constructor.apply(this, arguments);
        },

        beforeRender: function() {
        },

        render: function() {
            return this;
        },

        afterRender: function() {
            IframeUtils.iframeBinding(this);
        },

        toggleExpandCollapse: function(event) {
            var $target = $(event.target);
            // Don't propagate the event as it is possible that two views will both contain
            // this element, e.g. clicking on the element of a child view container in a parent.
            event.stopPropagation();
            event.preventDefault();
            ViewUtils.toggleExpandCollapse($target, this.options.collapsedClass);
        },

        /**
             * Loads the named template from the page, or logs an error if it fails.
             * @param name The name of the template.
             * @returns The loaded template.
             */
        loadTemplate: function(name) {
            return TemplateUtils.loadTemplate(name);
        }
    });

    return BaseView;
});
